<template>
  <el-form ref="form" v-if="model" :validate-on-rule-change="false" :model="model" :rules="rules" v-bind="$attrs">
    <template v-for="(item, index) in options" :key="index">
      <el-form-item :prop="item.prop" :label="item.label" v-if="!item.children || !item.children!.length" >
        <component 
          v-if="item.type !== 'upload' && item.type !== 'editor'"
          v-bind="item.attrs"
          :is="`el-${item.type}`"
          v-model="model[item.prop!]"
          :placeholder="item.placeholder">
        </component>
        <el-upload
          v-if="item.type === 'upload'"
          :id="item.id"
          v-bind="item.uploadAttrs"
          :on-preview="onPreview"
          :on-remove="onRemove"
          :on-success="onSuccess"
          :on-error="onError"
          :on-progress="onProgress"
          :on-change="onChange"
          :before-upload="beforeUpload"
          :before-remove="beforeRemove"
          :http-request="httpRequest"
          :on-exceed="onExceed">
            <slot name="uploadArea" :uploadId="item.id"></slot>
            <slot name="uploadTip"></slot>
        </el-upload>
        <div :id="item.id" v-if="item.type === 'editor'" style="border: 1px solid #ccc"></div>
      </el-form-item>
      <el-form-item :prop="item.prop" :label="item.label" v-if="item.children && item.children.length > 0" >
        <component v-bind="item.attrs" :is="`el-${item.type}`" v-model="model[item.prop!]" :placeholder="item.placeholder">
          <component
            v-for="(childItem, childIndex) in item.children"
            :key="childIndex"
            v-bind="childItem.attrs"
            :is="`el-${childItem.type}`"
            :label="childItem.label"
            :value="childItem.value"
            :placeholder="childItem.placeholder">
          </component>
        </component>
      </el-form-item>
    </template>
    <el-form-item>
      <slot name="action" :form="form" :model="model"></slot>
    </el-form-item>
  </el-form>
</template>

<script lang="ts" setup>
import { PropType, onMounted, ref, watch, nextTick } from 'vue'
import { FormOptions } from './types/type'
import { FormInstance } from 'element-plus'

import cloneDeep from 'lodash/cloneDeep'
import E from "wangeditor"

let emits = defineEmits([
  'on-preview',
  'on-remove',
  'on-success',
  'on-error',
  'on-progress',
  'on-change',
  'before-upload',
  'before-remove',
  'on-exceed'
])

let props = defineProps({
  // 表单的配置项
  options: {
    type: Array as PropType<FormOptions[]>,
    required: true
  },
  // 用户自定义上传方法
  httpRequest: {
    type: Function
  }
})

let model = ref<any>(null)
let rules = ref<any>(null)
let form = ref<FormInstance | null>()
let edit = ref()

const initForm = () => {
  if(props.options && props.options.length > 0){
    let m: any = {}
    let r: any = {}

    props.options.map((item: FormOptions) => {
      m[item.prop!] = item.value
      r[item.prop!] = item.rules

      if(item.type === 'editor'){
        // 初始化富文本
        nextTick(() => {
          if(document.getElementById('editor')){
            createEditor(item)
          }
        })
      }
    })

    model.value = cloneDeep(m)
    rules.value = cloneDeep(r)
  }
}

// 重置表单方法
const resetForm = () => {
  // 重置 element-plus 表单
  form.value!.resetFields()
  // 重置富文本编辑器的内容
  if(props.options && props.options.length > 0){
    // let editorList = props.options.filter( item => item.type === 'editor')
    let editorItem = props.options.find( item => item.type === 'editor')!
    edit.value.txt.html(editorItem.value)
  }
}

defineExpose({
  resetForm
})

onMounted(() => {
  initForm()
});

// 深度侦听 -> 父组件传递进来的 options 的变化
watch(() => props.options, () => {
  initForm()
}, {deep: true})

// 上传组件的所有方法
const onPreview = (file: File) => {
  emits('on-preview', file)
}
const onRemove = (file: File, fileList: FileList) => {
  emits('on-remove', { file, fileList })
}
const onSuccess = (response: any, file: File, fileList: FileList) => {
  // 上传图片成功 给表单上传项赋值
  // let uploadItem = props.options.find(item => item.type === 'upload')!
  // model.value[uploadItem.prop!] = { response, file, fileList }
  // console.log({ response, file, fileList })
  emits('on-success', { response, file, fileList })
}
const onError = (err: any, file: File, fileList: FileList) => {
  emits('on-error', { err, file, fileList, })
}
const onProgress = (event: any, file: File, fileList: FileList) => {
  console.log('event', event)
  emits('on-progress', { event, file, fileList })
}
const onChange = (file: File, fileList: FileList) => {
  emits('on-change', { file, fileList })
}
const beforeUpload = (file: File) => {
  emits('before-upload', file)
}
const beforeRemove = (file: File, fileList: FileList) => {
  emits('before-remove', { file, fileList })
}
const onExceed = (files: File, fileList: FileList) => {
  emits('on-exceed', { files, fileList })
}

// 富文本编辑器逻辑
const createEditor = (item:FormOptions) => {
  const editor = new E("#editor")
  editor.config.placeholder = item.placeholder!
  // 配置 onchange 回调函数
  editor.config.onchange = function (newHtml: string) {
    model.value[item.prop!] = newHtml
  };

  editor.create()
  // 初始化富文本的内容
  editor.txt.html(item.value)
  edit.value = editor
}
</script>

<style lang="scss" scoped>

</style>